home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
...taking it to the Macs!
/
...taking it to the Macs!.iso
/
Extras
/
ActiveX Mac SDK
/
ActiveX SDK
/
Sample Controls
/
PopupWindow
/
CPopupWindowControl.cpp
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
UTF-8
Wrap
Text File
|
1997-01-02
|
31.6 KB
|
1,215 lines
|
[
TEXT/CWIE
]
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl.h
//
// The PopupWindow control is designed to bring up a window whenever the
// mouse moves over the label designated as its source. Inside the window,
// PopupWindow renders the contents of the specified URL
//
// In this demonstration version, a mouse click in the specified label is
// required, pending implementatin of a mouseOver event.
//
// In this demonstration version, only pict files are rendered, pending
// implementation of MSHTML to render the contents of URL's.
//
// In this demonstration version, the image is rendered in a rect within
// the browser window rather than in a separate window.
//
#include "ocheaders.h"
#include "CBaseControl.h"
#include "CErrorControl.h" // included in header, listed here for documentation
#include "CBaseBindStatusCallback.h" // included in header, listed here for documentation
#include "CPopupWindowControl.h"
#include "BDMacros.h"
#include "BDUtils.h"
#include "FnAssert.h"
#include "CCPContainer.h"
#include "CPopupWindowError.h"
#include <stdio.h>
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::CPopupWindowControl
//
// constructor
//
CPopupWindowControl::CPopupWindowControl(void) : CBaseControl(), CBaseBindStatusCallback()
{
CCPContainer* containerObj = NULL;
long i; // used as index
#ifdef _DEBUG
HRESULT returnValue;
IUnknown* unk;
#endif
mFatalError = false; // To block action after failure.
mContainerP = NULL; // These are CBaseControl instance variables and should
mID[0] = 0; // be initialized in that constructor; but they aren't,
// and they get used before they're set.
mCookie = 0; // NOTE: if we ever actually use this for something, we need a
// list of them, since we allow connections to more than
// one specific sources.
mSourceName = NULL;
mConnectingComplete = false;
for ( i = 0; i < cMaxNumSourceControls; i++ ) // Reset the source names array.
{
mDesiredSourceNames[i] = NULL;
}
mNumDesiredSources = -1;
mNumFoundSources = 0;
mIsIdling = false;
mPict = NULL;
mPictIsLoaded = false;
mPopupWidth = 288; // Arbitrary for now. The Windows version sets it to the smaller
mPopupHeight = 288; // of the browser width or 1/3 of screen size
try
{
// Set a default name.
if ( !(SetName ( cPopupControlName )) )
throw CPopupWindowError ( DATA_ALLOCATION_ERROR );
if ( !(SetSourceName ( cEmptyCString )) )
throw CPopupWindowError ( DATA_ALLOCATION_ERROR );
#ifdef _DEBUG
// Since we're in debug code, don't add error handling here.
returnValue = QueryInterface ( IID_IUnknown, (void**) &unk );
GetObjectName ( unk, mThisName );
#endif
// Create the new connection point container object.
containerObj = new CCPContainer ( cNumConnections );
if ( !containerObj ) throw CPopupWindowError ( DATA_ALLOCATION_ERROR );
// Snag the interface pointer.
if ( FAILED ( containerObj->QueryInterface ( IID_IConnectionPointContainer,
&mCPContainerP ) ) )
throw CPopupWindowError ( NO_CNXN_PT_CONTAINER_ERROR );
if ( mCPContainerP )
{
// Allocate the connection points. We support 1 connection point.
if ( FAILED ( containerObj->AddConnectionPoint ( IID_IDidMenuEvents ) ) )
throw CPopupWindowError ( CANT_ADD_CNXN_PT_ERROR );
}
}
// error handling
catch ( CPopupWindowError &popupWindowError )
{
// Any failure here is catastrophic...
mFatalError = true;
popupWindowError.HandleError ();
}
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::~CPopupWindowControl
//
CPopupWindowControl::~CPopupWindowControl(void)
{
long i; // used as an index
if ( mIsIdling && mContainerSiteP )
{
// Remove our idler.
mContainerSiteP->SetIdleTime ( RemoveAllIdlers, 0 );
}
mID[0] = 0;
if ( mSourceName )
{
delete [] mSourceName;
mSourceName = NULL;
}
if ( mNumDesiredSources > 0 )
{
// Get rid of the strings in our source name list.
for ( i = 0; i < mNumDesiredSources; i++ )
{
ASSERT ( mDesiredSourceNames[i] != NULL, "Unexpected NULL source name.");
delete [] mDesiredSourceNames[i];
mDesiredSourceNames[i] = NULL;
}
mNumDesiredSources = -1;
}
if (mPict)
{
// Dispose the Picture, then the handle itself.
::DisposeHandle ( (Handle)((*mPict)->Pic) );
::DisposeHandle ( (Handle)mPict );
mPict = NULL;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::CBaseControl::IObjectWithSite::SetSite
//
STDMETHODIMP
CPopupWindowControl::SetSite ( IUnknown* inClientSite )
{
HRESULT returnValue;
returnValue = CBaseControl::SetSite ( inClientSite );
if ( mContainerSiteP )
{
mIsIdling = SUCCEEDED ( mContainerSiteP->SetIdleTime ( 0, 0 ) );
}
else
{
mIsIdling = false;
}
return returnValue;
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::IControl::Draw
//
STDMETHODIMP
CPopupWindowControl::Draw ( DrawContext* Context )
{
HRESULT returnValue = ResultFromScode ( S_OK );
if ( Context->DrawAspect != DVASPECT_CONTENT )
{
returnValue = ResultFromScode ( DV_E_DVASPECT );
}
return returnValue;
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::CBaseControl::IControl::DoIdle
//
STDMETHODIMP
CPopupWindowControl::DoIdle ( Uint32 IdleRefCon )
{
Boolean alreadyAdded;
IConnectionPointContainer* cnxnPtContainer = NULL;
IConnectionPoint* cnxnPt = NULL;
char controlName[256];
IEnumUnknown* enumUnknown;
long i; // used as an index
Boolean setAdviseSink;
IUnknown* testControl;
// if the client site has been set and we haven't yet tried to connect,
// enumerate the other controls in this container to find the one we want
// to connect to. We use the mConnectingComplete, mNumDesiredSources, and
// mNumFoundSources to handle the case where some of the controls we're
// attempting to connect to aren't enumerated yet because they haven't
// loaded yet. Once we find all the ones we're looking for, we stop
// looking.
//
// Note that we used to check to advisory cookie (mCookie) instead of
// mConnectingComplete, but in our case now, we want to be able to connect
// to multiple specific sources, so we need a separate flag.
#pragma unused ( IdleRefCon )
if ( mFatalError ) return ResultFromScode ( E_ABORT );
// if we don't have a container yet
// Get it now
if ( !mContainerP )
{
mContainerSiteP->GetContainer(&mContainerP);
mContainerP->AddRef();
}
if ( mContainerP && !mConnectingComplete )
{
try
{
// Enumerate the objects.
if ( FAILED ( mContainerP->EnumControls ( NULL,
OLECONTF_EMBEDDINGS,
&enumUnknown ) ) )
throw CPopupWindowError ( CANT_ENUM_OBJECTS_ERROR, this );
while ( enumUnknown->Next ( 1, &testControl, NULL ) == NOERROR )
{
// Get the name. Do it here instead of in a more nested scope so that
// we can use if for debugging.
GetObjectName ( testControl, controlName );
// Try to get a connection point container from the control.
testControl->QueryInterface ( IID_IConnectionPointContainer,
(void**) &cnxnPtContainer );
if ( cnxnPtContainer )
{
// It has one, so this may be it. See if this connection point container
// has a connection point with the outgoing interface we want.
cnxnPtContainer->FindConnectionPoint ( IID_IDoMenuEvents, &cnxnPt );
if ( cnxnPt )
{
// We got it, so set an advise connection on the outgoing interface.
setAdviseSink = false;
if ( mNumDesiredSources < 0 ) // We're not being specific.
{
// We don't really care about this if mNumDesiredSources < 0,
// but we'll do it anyway for the sake of completeness.
if ( !(AddSource ( controlName, &alreadyAdded )) )
throw CPopupWindowError ( DATA_ALLOCATION_ERROR );
setAdviseSink = true;
}
else
{
for ( i = 0; i < mNumDesiredSources; i++ )
{
ASSERT ( mDesiredSourceNames[i] != NULL,
"Unexpected NULL source name!" );
if ( STRINGS_ARE_EQUAL ( mDesiredSourceNames[i], controlName ) )
{
// It's one of our targets.
if ( !(AddSource ( controlName, &alreadyAdded )) )
throw CPopupWindowError ( DATA_ALLOCATION_ERROR );
if ( !alreadyAdded )
{
// We don't want to set the advise sink if we've
// found it in the past.
setAdviseSink = true;
}
// There's no need to loop any further once we've matched.
break;
}
}
}
if ( setAdviseSink )
{
if ( FAILED ( cnxnPt->Advise ( (IControl*)this, &mCookie ) ) )
{
throw CPopupWindowError ( CANT_ADVISE_CNXN_ERROR );
}
}
}
cnxnPtContainer->Release();
}
}
// Set a reminder to indicate whether we've already done our connecting.
mConnectingComplete = ( mNumDesiredSources < 0 ) ?
true : ( mNumDesiredSources == mNumFoundSources );
// Don't forget to release.
enumUnknown->Release();
}
catch ( CPopupWindowError &popupWindowError )
{
// Any failure here is fatal, because if we can't connect we can't pop up.
mFatalError = true;
popupWindowError.HandleError ();
}
}
if ( mConnectingComplete )
{
// We're hooked up, so discontinue idling.
mContainerSiteP->SetIdleTime ( RemoveAllIdlers, 0 );
mIsIdling = false;
}
if ( mPendingDraw )
{
// We have a draw pending, so force a draw.
InvalAllContexts ();
}
return ResultFromScode ( S_OK );
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::OnStopBinding
//
STDMETHODIMP
CPopupWindowControl::OnStopBinding(ErrorCode Result, const Char8* Error)
{
Rect boundsRect;
HRESULT returnValue;
if ( mFatalError ) return ResultFromScode ( E_ABORT );
returnValue = CBaseBindStatusCallback::OnStopBinding ( Result, Error ); // shouldn't fail
if (mBindSiteP)
{
mBindSiteP->Release(); // shouldn't fail
mBindSiteP = 0;
}
// That should be end of file. Prepare the pict to be drawn.
mPictIsLoaded = true;
try
{
if ( ( mPict == NULL ) || ( (*mPict)->Pic == NULL ) )
throw CPopupWindowError ( EOF_AND_NO_IMAGE_ERROR );
boundsRect = (*(*mPict)->Pic)->picFrame;
::OffsetRect( &boundsRect, -boundsRect.left, -boundsRect.top );
(*mPict)->PicRect = boundsRect;
returnValue = ResultFromScode ( S_OK );
}
catch ( CPopupWindowError &popupWindowError )
{
// Any failure here is fatal, because if we don't have an image after
// the data has all been delivered, there's nothing to pop up.
mFatalError = true;
popupWindowError.HandleError ();
returnValue = ResultFromScode ( E_FAIL );
}
return returnValue;
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::OnDataAvailable
//
// OnDataAvailable is a callback routine which gets called when there is data
// available in the input stream. The amount of data is specified.
// OnDataAvailable grabs "Size" bytes from the "StgMedium" (storage medium)
// and places it into the target buffer mPict.
//
// OnDataAvailable will be called repeatedly until there is no more data
// available in the input stream. Note that OnStopBinding gets called at EOF.
//
// This method increases the size of the inbut buffer handle "mPict" by "Size"
// bytes each time it's called.
//
STDMETHODIMP
CPopupWindowControl::OnDataAvailable(
Uint32 BSCF,
Uint32 Size,
FORMATETC* FormatEtc,
STGMEDIUM* StgMedium)
{
unsigned long newSize;
HRESULT returnValue = ResultFromScode ( S_OK );
Handle TargetPicHandle = NULL;
if ( mFatalError ) return ResultFromScode ( E_ABORT );
// CBaseBindStatusCallback::OnDataAvailable sets "mSize" based on "Size". (This should
// never fail.)
returnValue = CBaseBindStatusCallback::OnDataAvailable ( BSCF, Size, FormatEtc, StgMedium );
if ( StgMedium->tymed == TYMED_FILE )
{
CoTaskMemFree ( StgMedium->lpszFileName );
if ( StgMedium->pUnkForRelease != NULL )
{
StgMedium->pUnkForRelease->Release (); // Should not fail.
}
}
else if ( StgMedium->tymed == TYMED_ISTREAM ) // Stream I/O
{
try
{
// Make sure that the picture record and its buffer are allocated and have
// enough space to read the available data.
if ( !(AllocatePictBuffer ()) ) throw CPopupWindowError ( DATA_ALLOCATION_ERROR );
mPictBytesRemaining = mDataSize;
if ( mPictBytesSoFar < cPictHeaderSize )
{
// Read the pict header. (Just read it into the PicHandle, and we'll
// overwrite it when we get the real picture data.)
if ( !(ReadPictHeader ( StgMedium )) )
throw CPopupWindowError ( IMAGE_READ_ERROR );
if ( mPictBytesSoFar >= cPictHeaderSize )
{
// We're going to throw away the header, so reset the buffer
// handle size.
TargetPicHandle = (Handle)((*mPict)->Pic);
newSize = ::GetHandleSize ( TargetPicHandle ) - cPictHeaderSize;
::SetHandleSize ( TargetPicHandle, newSize );
// Setting a handle smaller shouldn't fail...
if ( ::GetHandleSize ( TargetPicHandle ) != newSize )
throw CPopupWindowError ( DATA_REALLOCATION_ERROR );
}
}
// It's possible we didn't read the entire picture header the first time, so
// we can't assume it's okay to go ahead and start reading data.
if ( ( mPictBytesSoFar >= cPictHeaderSize ) && ( mDataSize > 0 ) )
{
// Read the available data into the picture buffer.
if ( !(ReadPictData ( StgMedium )) )
throw CPopupWindowError ( IMAGE_READ_ERROR );
}
}
catch ( CPopupWindowError &popupWindowError )
{
// Any failure here is fatal, because we don't have an image to pop up.
mFatalError = true;
popupWindowError.HandleError ();
returnValue = ResultFromScode ( E_FAIL );
}
}
return returnValue;
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::IDoMenuEvents::Popup
//
STDMETHODIMP
CPopupWindowControl::Popup ( IUnknown* Source, PlatformEvent* Event )
{
#pragma unused ( Source )
DrawContext Context;
GDHandle currentGraphicsDevice;
GrafPtr currentGrafPort;
pictInfo CurrentPict;
EventRecord dummyEvent;
StringPtr ErrorMessage = NULL;
short innermost;
Point mouseCoord;
Rect myRect;
RgnHandle oldClipRgn;
Point screenBotRight;
Rect screenRect;
Point screenTopLeft;
if ( mFatalError ) return ResultFromScode ( E_ABORT );
// Get the target rect.
mouseCoord = Event->where;
::GlobalToLocal ( &mouseCoord );
SetRect ( &myRect, mouseCoord.h,
mouseCoord.v,
mouseCoord.h + mPopupWidth - 1,
mouseCoord.v + mPopupHeight - 1);
::GetPort ( ¤tGrafPort );
// Get the current screen information.
currentGraphicsDevice = ::GetGDevice ();
screenRect = (**currentGraphicsDevice).gdRect;
::SetPt ( &screenTopLeft, screenRect.left, screenRect.top + GetMBarHeight () );
::SetPt ( &screenBotRight, screenRect.right, screenRect.bottom );
::GlobalToLocal ( &screenTopLeft );
::GlobalToLocal ( &screenBotRight );
::Pt2Rect ( screenTopLeft, screenBotRight, &screenRect );
//mPopupWidth = (screenRect.right - screenRect.left)/3; // 1/3 of screen size
//mPopupHeight = (screenRect.bottom - screenRect.top)/3; // 1/3 of screen size
// Force myRect onscreen and into the window.
innermost = MIN ( currentGrafPort->portRect.bottom, screenRect.bottom );
if ( myRect.bottom > innermost )
{
OffsetRect ( &myRect, 0, innermost - myRect.bottom );
}
innermost = MIN ( currentGrafPort->portRect.right, screenRect.right );
if ( myRect.right > innermost )
{
OffsetRect ( &myRect, innermost - myRect.right, 0 );
}
innermost = MAX ( currentGrafPort->portRect.top, screenRect.top );
if ( myRect.top < innermost )
{
OffsetRect ( &myRect, 0, innermost - myRect.top );
}
innermost = MAX ( currentGrafPort->portRect.left, screenRect.left );
if ( myRect.left < innermost )
{
OffsetRect ( &myRect, innermost - myRect.left, 0 );
}
// Set the clip rect to myRect, including one pixel for the frame.
::InsetRect ( &myRect, -1, -1 );
oldClipRgn = ::NewRgn ();
::GetClip ( oldClipRgn );
::ClipRect ( &myRect );
::FrameRect ( &myRect );
// Draw inside the frame.
::InsetRect ( &myRect, 1, 1 );
::ClipRect ( &myRect );
if ( mPictIsLoaded )
{
// Grab the pict handle from the pict info.
CurrentPict = *(*mPict);
if ( CurrentPict.Pic )
{
::EraseRect ( &myRect );
DrawPict ( currentGrafPort, &myRect, CurrentPict.Pic, &CurrentPict.PicRect );
// Wait for a mouse or key event to happen. Note that we eat that event.
Boolean done = false;
while (!done)
{
WaitNextEvent ( everyEvent, &dummyEvent, 0, nil );
switch ( dummyEvent.what )
{
case mouseDown:
case keyDown:
case autoKey:
done = true;
break;
}
}
// Invalidate the rect so it gets redrawn.
::InsetRect ( &myRect, -1, -1 ); // To get the frame, too.
::InvalRect ( &myRect);
}
else
{
ErrorMessage = "\pNot Enough Ram to store picture.";
}
}
else
{
ErrorMessage = "\pPicture not loaded yet.";
}
if ( ErrorMessage )
{
mDrawPort = (GrafPtr)(Context.Port);
mPendingDraw = true;
// Draw the error message.
::TextFace ( bold );
::TextFont ( 0 );
::TextSize ( 12 );
::MoveTo (
(Context.Location.right +
Context.Location.left -
StringWidth(ErrorMessage))/2,
(Context.Location.bottom + Context.Location.top + 12)/2 );
::DrawString ( ErrorMessage );
}
else
{
// Stop invalidating the popup rect.
mPendingDraw = false;
}
// Restore the old clipping region before we go.
::SetClip ( oldClipRgn );
::DisposeRgn ( oldClipRgn );
return ResultFromScode ( S_OK );
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::IPersistPropertyBag::Load
//
STDMETHODIMP
CPopupWindowControl::Load ( IPropertyBag* PropBag, IErrorLog* ErrorLog )
{
LPVOID dummy;
long i; // used for an index
DWORD length;
char propertyNameString[64];
char propertyString[Str255BufferLength];
HRESULT returnValue = ResultFromScode ( S_OK );
LPMONIKER URLMoniker = NULL;
VARIANT v;
if ( mFatalError ) return ResultFromScode ( E_ABORT );
// Try to load in each property. If we can't get it, then leave things at the default.
// Loop through all the sourceobject[x] parameters. It's possible there's only one,
// with no [x].
strcpy ( propertyNameString, cSourceObjectStr );
try
{
if ( ::LoadPropertyString (
PropBag, propertyNameString, propertyString, Str255StringLength, ErrorLog ) )
{
if ( !(AddDesiredSourceName ( propertyString )) )
throw CPopupWindowError ( DATA_ALLOCATION_ERROR );
}
else
{
for ( i = 0; i <= cMaxNumSourceControls; i++ )
{
sprintf ( propertyNameString, "%s[%ld]", cSourceObjectStr, i );
if ( ::LoadPropertyString (
PropBag, propertyNameString, propertyString, Str255StringLength, ErrorLog ) )
{
if ( !(AddDesiredSourceName ( propertyString )) )
throw CPopupWindowError ( DATA_ALLOCATION_ERROR );
}
}
}
v.vt = VT_BSTR;
v.bstrVal = NULL;
// Try to load in the property. If we can't get it, then leave things at their default.
PropBag->Read ( "data", &v, ErrorLog );
if ( v.bstrVal )
{
length = *((LPDWORD)(v.bstrVal)) ;
strcpy ( (Char8*)mDataURL, v.bstrVal + sizeof(Uint32) );
CoTaskMemFree ( v.bstrVal );
}
mUnkOuterP->QueryInterface ( IID_IBindHost, (LPVOID *) &mBindSiteP );
if ( mBindSiteP )
{
mBindSiteP->CreateMoniker ( (LPOLESTR)mDataURL, NULL, &URLMoniker, 0 );
if( URLMoniker )
{
mBindSiteP->MonikerBindToStorage ( URLMoniker, NULL, this, IID_IStream, &dummy );
URLMoniker->Release ();
}
}
}
catch ( CPopupWindowError &popupWindowError )
{
// Any failure here is fatal, because we couldn't load the control parameters.
mFatalError = true;
popupWindowError.HandleError ();
returnValue = ResultFromScode ( E_FAIL );
}
return returnValue;
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::IUnknown::QueryInterface
//
// Returns a pointer to the specified interface on a component to which a
// client currently holds an interface pointer.
//
STDMETHODIMP
CPopupWindowControl::QueryInterface(REFIID RefID, void** Obj)
{
HRESULT returnValue = ResultFromScode ( S_OK );
if ( mFatalError ) return ResultFromScode ( E_ABORT );
if ( RefID == IID_IDoMenuEvents ) // an incoming interface
{
*Obj = (void*)((IDoMenuEvents*)this);
AddRef ();
}
else
{
returnValue = CBaseControl::QueryInterface ( RefID, Obj );
}
return returnValue;
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::SetName
//
// SetName returns true if it successfully sets the name, false otherwise. It
// can fail to allocate memory for the name.
Boolean CPopupWindowControl::SetName ( const char * theName )
{
strcpy ( (char*)(&mID[1]), theName );
mID[0] = strlen(theName);
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::SetSourceName
//
Boolean CPopupWindowControl::SetSourceName ( const char * theName )
{
Boolean returnValue = true;
try
{
if ( mSourceName == NULL )
{
mSourceName = (char *) new char[Str255BufferLength];
if ( mSourceName == NULL ) throw CPopupWindowError ( DATA_ALLOCATION_ERROR );
}
strcpy ( mSourceName, theName );
}
catch ( CPopupWindowError &popupWindowError )
{
// Any failure here is fatal, because we won't be able to connect to another
// control by name.
mFatalError = true;
popupWindowError.HandleError ();
returnValue = false;
}
return returnValue;
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::AddDesiredSourceName
//
// AddDesiredSourceName returns true if it successfully added the name to the
// array of source names, false otherwise.
//
Boolean CPopupWindowControl::AddDesiredSourceName ( const char * theName )
{
long currentIndex;
long nextIndex;
Boolean returnValue = true;
ASSERT ( theName != NULL, "Unexpected NULL source name in AddDesiredSourceName" );
currentIndex = ( mNumDesiredSources < 0 ) ? 0 : mNumDesiredSources;
nextIndex = currentIndex + 1;
if ( nextIndex < cMaxNumSourceControls )
{
try
{
mDesiredSourceNames[currentIndex] = new char[strlen(theName)+1];
if ( mDesiredSourceNames[currentIndex] == NULL )
throw CPopupWindowError ( DATA_ALLOCATION_ERROR );
strcpy(mDesiredSourceNames[currentIndex], theName);
mNumDesiredSources = nextIndex;
}
catch ( CPopupWindowError &popupWindowError )
{
// Any failure here is fatal, because we don't another control to connect to.
mFatalError = true;
popupWindowError.HandleError ();
returnValue = false;
}
}
return returnValue;
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::AddSource
//
// AddSource sets the alreadyFoundIt parameter to true if it already exists in
// the list.
//
// AddSource returns false if it has an allocation error, true otherwise.
Boolean CPopupWindowControl::AddSource ( const char * sourceName, Boolean * alreadyFoundIt )
{
long i; // used as an index
Boolean returnValue = true;
// Only add the source to our list of found sources if we haven't already done so.
*alreadyFoundIt = false;
for ( i = 0; i < mNumFoundSources; i++ )
{
if ( STRINGS_ARE_EQUAL ( mFoundSourceNames[i], sourceName ) )
{
// It's already in our list.
*alreadyFoundIt = true;
break;
}
}
if ( !(*alreadyFoundIt) )
{
try
{
mFoundSourceNames[mNumFoundSources] = new char[strlen(sourceName)+1];
if ( mFoundSourceNames[mNumFoundSources] == NULL)
throw CPopupWindowError ( DATA_ALLOCATION_ERROR );
strcpy(mFoundSourceNames[mNumFoundSources], sourceName);
mNumFoundSources++;
}
catch ( CPopupWindowError &popupWindowError )
{
// Any failure here is fatal, because we don't have a source control.
mFatalError = true;
popupWindowError.HandleError ();
returnValue = false;
}
}
return returnValue;
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::IsSource
//
Boolean CPopupWindowControl::IsSource ( IUnknown * unk )
{
Boolean isSource = false;
char sourceName[256];
if ( mNumDesiredSources == -1 ) // We're not being specific.
{
isSource = true;
}
else
{
GetObjectName ( unk, sourceName );
if ( sourceName )
{
isSource = IsSource ( sourceName );
}
}
return isSource;
}
Boolean CPopupWindowControl::IsSource ( const char * sourceName )
{
long i; // used as an index
Boolean isSource = false;
if ( mNumDesiredSources == -1 ) // We're not being specific.
{
isSource = true;
}
else
{
for ( i = 0; i < mNumFoundSources; i++ )
{
ASSERT(mFoundSourceNames[i] != NULL, "Unexpected NULL source name!");
if ( STRINGS_ARE_EQUAL ( mFoundSourceNames[i], sourceName ) )
{
// It's one of our targets.
isSource = true;
break; // There's no need to loop any further once we've matched.
}
}
}
return isSource;
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::DrawPict
//
void CPopupWindowControl::DrawPict (
GrafPtr pGrafDraw,
Rect* lprect,
PicHandle Pic,
Rect* PictRect)
{
#pragma unused (pGrafDraw)
Rect theRect;
theRect.top = lprect->top;
theRect.left = lprect->left;
theRect.bottom = lprect->top + PictRect->bottom;
theRect.right = lprect->left + PictRect->right;
::DrawPicture ( Pic, &theRect );
return;
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::AllocatePictBuffer
//
// AllocatePictBuffer allocates a buffer in memory before the picture is read
// in, and each time new data is available AllocatePictBuffer bumps up the
// buffer size.
//
// AllocatePictBuffer returns true if the allocation was successful, false
// otherwise.
//
Boolean CPopupWindowControl::AllocatePictBuffer ( void )
{
unsigned long newSize;
Boolean returnValue = true;
Handle TargetPicHandle = NULL;
try
{
if ( ( mPict == NULL) && ( mDataSize > 0 ) )
{
// Allocate memory for a new picture record and its buffer.
mPict = (pictInfo**)(::NewHandle ( sizeof(pictInfo) ));
if ( mPict == NULL ) throw CPopupWindowError ( DATA_ALLOCATION_ERROR );
::HLock ( (Handle)mPict );
(**mPict).Pic = (PicHandle)(::NewHandle ( mDataSize ));
::HUnlock( (Handle)mPict );
if ( (**mPict).Pic == NULL ) throw CPopupWindowError ( DATA_ALLOCATION_ERROR );
// Let everyone know we're just starting.
mPictIsLoaded = false;
mPictBytesSoFar = 0;
}
else if ( mDataSize > 0 ) // ( mPict != NULL ); don't bother if the amount of data
{ // available is zero.
if ( (**mPict).Pic != NULL )
{
// Bump up the memory for the picture buffer so we have space to read into.
TargetPicHandle = (Handle)((*mPict)->Pic);
::SetHandleSize ( TargetPicHandle, mPictBytesSoFar + mDataSize );
newSize = ::GetHandleSize ( TargetPicHandle );
if ( newSize != mPictBytesSoFar + mDataSize )
throw CPopupWindowError ( DATA_REALLOCATION_ERROR );
}
}
}
catch ( CPopupWindowError &popupWindowError )
{
// Any failure here is fatal; because if we don't have enough memory
// for an image buffer, we can't render the image. Duh.
mFatalError = true;
popupWindowError.HandleError ();
returnValue = false;
}
return returnValue;
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::ReadPictHeader
//
// ReadPictHeader reads the pict header from the input stream into the pict
// buffer.
//
// ReadPictHeader is called by the OnDataAvailable callback, so it is possible
// all of the data isn't available when ReadPictHeader is called. If not, it
// will continue reading when it is called repeatedly until all of the pict
// header has been read.
//
// ReadPictHeader returns true if successful, false otherwise.
//
Boolean CPopupWindowControl::ReadPictHeader ( STGMEDIUM* StorageMedium )
{
unsigned long actualBytesRead = 0;
unsigned long BytesToRead = 0L;
unsigned long headerBytesRemaining = 0;
HRESULT resultCode = ResultFromScode ( S_OK );
Boolean returnValue = true;
char* Target = NULL;
Handle TargetPicHandle = NULL;
TargetPicHandle = (Handle)((*mPict)->Pic);
::HLock ( TargetPicHandle );
Target = *TargetPicHandle;
headerBytesRemaining = ( cPictHeaderSize - mPictBytesSoFar > 0 ) ?
cPictHeaderSize - mPictBytesSoFar : 0;
BytesToRead = ( headerBytesRemaining < mDataSize ) ? headerBytesRemaining : mDataSize;
try
{
resultCode = StorageMedium->pstm->Read ( Target,
BytesToRead,
&actualBytesRead );
::HUnlock ( TargetPicHandle );
if ( FAILED ( resultCode ) ) throw CPopupWindowError ( IMAGE_READ_ERROR );
mPictBytesRemaining -= actualBytesRead;
mPictBytesSoFar += actualBytesRead;
}
catch ( CPopupWindowError &popupWindowError )
{
// Are we guaranteed that a failure here is fatal?
mFatalError = true;
popupWindowError.HandleError ();
returnValue = false;
}
return returnValue;
}
///////////////////////////////////////////////////////////////////////////////
//
// CPopupWindowControl::ReadPictData
//
// ReadPictData reads the pict data from the input stream into the pict buffer.
//
// ReadPictData is called by the OnDataAvailable callback, so it is possible
// all of the data isn't available when ReadPictData is called. If not, it
// will continue reading when it is called repeatedly until all of the pict
// data has been read.
//
// ReadPictData returns true if it is successful, false otherwise.
//
Boolean CPopupWindowControl::ReadPictData ( STGMEDIUM* StorageMedium )
{
unsigned long actualBytesRead = 0;
unsigned long BytesToRead = 0L;
HRESULT resultCode = S_OK;
Boolean returnValue = true;
char* Target = NULL;
Handle TargetPicHandle = NULL;
// Read the available data into the picture buffer.
TargetPicHandle = (Handle)((*mPict)->Pic);
::HLock ( TargetPicHandle );
BytesToRead = mPictBytesRemaining;
// Advance the target through the PicHandle as we go. Note that we overwrite
// the pict header data we previously read into the target buffer.
Target = *TargetPicHandle + mPictBytesSoFar - cPictHeaderSize;
try
{
resultCode = StorageMedium->pstm->Read ( Target,
BytesToRead,
&actualBytesRead );
::HUnlock ( TargetPicHandle );
if ( FAILED ( resultCode ) ) throw CPopupWindowError ( IMAGE_READ_ERROR );
mPictBytesRemaining -= actualBytesRead;
mPictBytesSoFar += actualBytesRead;
}
catch ( CPopupWindowError &popupWindowError )
{
// Are we guaranteed that a failure here is fatal?
mFatalError = true;
popupWindowError.HandleError ();
returnValue = false;
}
return returnValue;
}